/**
 *                             _ooOoo_
 *                            o8888888o
 *                            88" . "88
 *                            (| -_- |)
 *                            O\  =  /O
 *                         ____/`---'\____
 *                       .'  \\|     |//  `.
 *                      /  \\|||  :  |||//  \
 *                     /  _||||| -:- |||||-  \
 *                     |   | \\\  -  /// |   |
 *                     | \_|  ''\---/''  |   |
 *                     \  .-\__  `-`  ___/-. /
 *                   ___`. .'  /--.--\  `. . __
 *                ."" '<  `.___\_<|>_/___.'  >'"".
 *               | | :  `- \`.;`\ _ /`;.`/ - ` : | |
 *               \  \ `-.   \_ __\ /__ _/   .-` /  /
 *          ======`-.____`-.___\_____/___.-`____.-'======
 *                             `=---='
 *          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 *                     佛祖保佑        永无BUG
 *            佛曰:
 *                   写字楼里写字间，写字间里程序员；
 *                   程序人员写程序，又拿程序换酒钱。
 *                   酒醒只在网上坐，酒醉还来网下眠；
 *                   酒醉酒醒日复日，网上网下年复年。
 *                   但愿老死电脑间，不愿鞠躬老板前；
 *                   奔驰宝马贵者趣，公交自行程序员。
 *                   别人笑我忒疯癫，我笑自己命太贱；
 *                   不见满街漂亮妹，哪个归得程序员？
*/

#include <stdio.h>
#include <unistd.h>
#include <string.h>

#include <malloc.h>

#include <hi_types_base.h>
#include <hi_io.h>
#include <hi_gpio.h>

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "rc522.h"
#include "list.h"
#include "uart.h"
#include "time.h"
#include "display_screen.h"

#include "wifi_config.h"
#include <oc_mqtt_profile_package.h>
#include "oc_mqtt.h"
#include "mqtt_config.h"

#include "nv.h"
#include <hi_flash.h>
#include <hi_task.h>
#include <hi_stdlib.h>
#include <hi_watchdog.h>
#include <hi_early_debug.h>
#include <hi_time.h>

/** 引脚连接
 *   SPI0
 * SCK  GPIO6
 * MISO GPIO7
 * MOSI GPIO8
 * NSS  GPIO9
 * PST  GPIO10
 * 
 *   UART1
 * TXD  GPIO0
 * RXD  GPIO1
 * 
 *   串口屏
 * 屏     USB to TTL
 * GND    棕色
 * RX     橙色
 * TX     红色
 * +5V    黄色
*/ 


#define SCANCARD_IOT_STACK_SIZE 1024*50
#define SCANCARD_IOT_PRIO 26
#define FINDCARD_STACK_SIZE 1024*20
#define FINDCARD_PRIO 25
#define MQTT_STACK_SIZE 1024*10
#define MQTT_PRIO 23
#define TIME_CONTROL_STACK_SIZE 1024*5
#define TIME_CONTROL_PRIO 24

// #define DEBUG 0


// RC522 用户ID、权限数据库(链表)
// 共享资源 每次使用要(互斥量)申请才能使用
LinkList RC522_Database;
// 目前用户数量(包含Root和Admin、User)
unsigned char g_user_num = 0;
// 系统时间
struct sys_time Sys_Time;
// 打印时间
struct scancard_time ScanCard_Time;
// 考勤记录(信息)
struct sys_record_info ScanRecord_Info[50];
// 记录的考勤信息，初始化为0，表示此时拥有0条信息，下一次的有效信息是下标为0的信息
unsigned char record_num = 0;
// 互斥量ID(要全局)
osMutexId_t mutex_id1; //锁住数据库，不让其他线程操作
osMutexId_t mutex_id2; //锁住MQTT线程，每打卡成功一次，就释放一次，MQTT就占用一次。其余时间在等待互斥量。
// 消息队列(要全局)
#define MSGQUEUE_OBJECTS 16 // number of Message Queue Objects
#define MSGQUEUE_OBJECTS_SIZE 100 // size of Message Queue Objects
// MQTT 线程ID
osThreadId_t mqtt_thread_id;
// MQTT 数据对象
MSGQUEUE_OBJ_t msg;
// message queue id
osMessageQueueId_t mid_MsgQueue;
// MQTT 是否使能，与Wifi连接与断开同步
// disable: Wifi & MQTT 都断开(mqtt_enable清0)
// enable: Wifi & MQTT 都连接(mqtt_enable置1)
// disable->enable: 连接wifi后
//     Wifi端: mqtt_enable置1，恢复阻塞MQTT线程(进入二层while(1)循环)
//     MQTT端: 需要重新注册设备相关信息
// enable->disable: 断开wifi后
//     Wifi端: 阻塞MQTT线程，mqtt_enable清0
//     MQTT端：无
bool mqtt_enable = 0;
//
// struct bp_oc_info oc_info;


/* Wi-Fi */
// #define WIFI_SSID_LEN 20
// #define WIFI_PASSWD_LEN 20
//Wi-Fi ssid
// char ssid[WIFI_SSID_LEN] = "nova 5z";
//Wi-Fi passwd
// char passwd[WIFI_PASSWD_LEN] = "12345678";
//Wi-Fi 连接状态: 是否已连接
bool wifi_connected = 0;

//系统第一次上电(下载完程序的第一次上电)
//默认是第一次
bool sys_Running_First = 1;

//系统时间显示
bool sys_Time_Display = 1;



//串口屏指令集
const display_screen_cmd g_display_screen_cmd_set_tbl[] = {
/** 设置 */
    {"settings", 8, (display_screen_cmd_call_back_func)Settings_Card},

/** 考勤记录 */
#ifdef DISPLAY_SCREEN_SCANRECORD
    {"record", 6, (display_screen_cmd_call_back_func)Scan_Record},
#endif

/** 添加用户 */
#ifdef DISPLAY_SCREEN_ADDUSER
    {"adduser", 7, (display_screen_cmd_call_back_func)Add_Card},
#endif

/** 删除用户 */
#ifdef DISPLAY_SCREEN_DELUSER
    {"deluser", 7, (display_screen_cmd_call_back_func)Del_Card},
#endif

/** 登录管理 */
#ifdef DISPLAY_SCREEN_LOGIN
    {"login", 5, (display_screen_cmd_call_back_func)Login_Card},
#endif

/** 权限管理 */
#ifdef DISPLAY_SCREEN_PERMISSION
    {"permission", 10, (display_screen_cmd_call_back_func)Permission_Card},
#endif

/** 其他指令：默认处理 */
    // {"others", 6, (display_screen_cmd_call_back_func)Others_Conditions},
};

//串口屏指令数
#define DISPLAY_SCREEN_GENERAL_CMD_NUM (sizeof(g_display_screen_cmd_set_tbl) / sizeof(g_display_screen_cmd_set_tbl[0]))




void Sys_Init(void)
{    
    
    RC522_Init();
    printf("RC522_Init success\r\n");

    Uart_Init(); //串口1初始化

    // 在没有掉电存储时使用，如果有了掉电存储记得注释掉
    // 并且加一个NV操作读取Flash的数据到RC522_Database
    Database_Init();

    // NV_Test2();
    // NV_Test3(); //KV 测试成功


    // PrintfList(RC522_Database);

    /* 系统时间 初始化 */
    //年月日     时分秒
    //2021/3/15 18:30:20
    Sys_Time.sys_time_years = 2021;
    Sys_Time.sys_time_months = 5;
    Sys_Time.sys_time_days = 21;
    Sys_Time.sys_time_hours = 18;
    Sys_Time.sys_time_minutes = 30;
    Sys_Time.sys_time_seconds = 0;

    if(sys_Running_First)
	{
        /* 打卡时间 初始化 */
        //早上 8:29:59  下午 18:29:59
        ScanCard_Time.morning_time_hours = 8;
        ScanCard_Time.morning_time_minutes = 29;
        ScanCard_Time.morning_time_seconds = 59;
        ScanCard_Time.afternoon_time_hours = 18;
        ScanCard_Time.afternoon_time_minutes = 29;
        ScanCard_Time.afternoon_time_seconds = 59;

        hi_flash_erase(FLASH_SCANCARD_TIME, 4096);
        Flash_Write_Scancard(FLASH_SCANCARD_TIME, HI_FALSE);

        sys_Running_First = 0;
    }
    Flash_Read_Scancard(FLASH_SCANCARD_TIME);

    //串口屏 返回 main 界面
    Display_Screen_Write((hi_u8 *)"page main");

    /* Wi-Fi 未连接状态 */
    // 全局 wifi 图标由连通变为禁止状态
	Display_Screen_Write((hi_u8 *)"main.p0.pic=2");
    // 全局 Disconnect 按钮变为 Connect ，为下次连接做准备
    Display_Screen_Write((hi_u8 *)"wifi.b0.txt=\"Connect\"");

    // Wifi Test
    // Wifi_Connect_Test();
}

void ReceiveCmd_Pros(void)
{
	unsigned char Rxdata[30];
	unsigned int Rxdata_len;
    unsigned char i;
    char ret;

	ret = Display_Screen_Read_Timeout(Rxdata, &Rxdata_len, 50); //串口接收来自串口屏的指令cmd
    if(ret == 0)
    {
        for(i = 0; i < DISPLAY_SCREEN_GENERAL_CMD_NUM; i++)
        {
            if(strncmp((const char *)Rxdata, (const char *)g_display_screen_cmd_set_tbl[i].display_screen_cmd_name, Rxdata_len) == 0) //查找指令cmd
            {
                Display_Screen_cmd_callback(g_display_screen_cmd_set_tbl[i].display_screen_cmd_func);
                break;
            }
        }
    }
}


/* 主线程  根据串口屏的指令执行不同的功能，回调不同的函数 */
void scancard_iot_thread(const char *arg)
{
    arg = arg;

    usleep(500000); //等待系统信息打印完

    Sys_Init();

    usleep(1000000);

    while(1)
    {
        osMutexAcquire(mutex_id1, osWaitForever); //阻塞 互斥量
        ReceiveCmd_Pros();                        //接收串口屏指令并处理
        osMutexRelease(mutex_id1);                //释放 互斥量

#ifdef DEBUG
        printf("usleep scancard_iot_thread 10ms.\r\n\r\n");
#endif
        usleep(10000);
    }
}

/* 刷卡(打卡)线程 */
void findcard_thread(const char *arg)
{
    arg = arg;

    usleep(1000000); //等待系统信息打印完 主线程初始化完

    while(1)
    {
        osMutexAcquire(mutex_id1, osWaitForever); //阻塞 互斥量
        Scan_Card();                              //刷卡 打卡
        osMutexRelease(mutex_id1);                //释放 互斥量

#ifdef DEBUG
        printf("usleep findcard_thread 2000ms.\r\n\r\n");
#endif
        usleep(2000000);
    }
}

/* MQTT 线程 */
void MQTT_thread(const char *arg)
{
    app_msg_t *app_msg;
    
    arg = arg;

    usleep(500000); //等待系统信息打印完 主线程初始化完

    while(1)
    {
        if(mqtt_enable)
        {
            // /* MQTT 设备注册 */
            device_info_init(CLIENT_ID, USERNAME, PASSWORD); // 初始化设备信息
            oc_mqtt_init(); //华为IoT平台 初始化
            oc_set_cmd_rsp_cb(oc_cmd_rsp_cb);

            mqtt_enable = 0;
        }
    
        //Wi-Fi联网的前提下，才去接收消息队列的消息，避免设备未联网情况下，把消息队列的消息接收掉了，而不能上传到云平台
        if(wifi_connected)
        {
            app_msg = NULL;

            //超时时间:0
            (void)osMessageQueueGet(mid_MsgQueue, (void **)&app_msg, NULL, 0U); // MQTT 发布消息
            if(app_msg != NULL)
            {
                switch (app_msg->msg_type)
                {
                    case en_msg_cmd: //来自云端的命令
                        break;
                    case en_msg_report:
                        deal_report_msg(&app_msg->msg.report); //发布消息到云端
                        break;
                    default:
                        break;
                }
                free(app_msg);
            }
        }

        printf("usleep MQTT_thread 3s.\r\n\r\n"); //3s上报一次，因为有消息队列，所以可以缓冲
        usleep(3000000);
    }
}

/* 限时控制线程  每秒处理一次数据库的时间控制 */
void time_control_thread(const char *arg)
{
	// int connect_status;
    arg = arg;

    usleep(1000000); //等待系统信息打印完 主线程初始化完

    while(1)
    {
        // if(wifi_connected == 0)
        // {

        //     connect_status = Wifi_Connect(ssid, passwd);
        //     if(connect_status == 0)
        //     {
        //         // osThreadResume(mqtt_thread_id); //恢复MQTT线程，MQTT线程优先级最高会立即执行
        //         wifi_connected = 1;
        //         mqtt_enable = 1; //重新进行设备注册后，再次进入内层while(mqtt_enable)循环
        //         //连接成功，密码正确
        //         Display_Screen_Write((hi_u8 *)"wifi.b0.txt=\"Disconnect\""); //全局 Connect 按钮变为 Disconnect ，为断开连接做准备
        //         Display_Screen_Write((hi_u8 *)"p0.pic=1"); //page wifi 私有 wifi 图标由禁止变为连通状态
        //         Display_Screen_Write((hi_u8 *)"main.p0.pic=1"); //page main 全局 wifi 图标由禁止变为连通状态
        //     }
        //     else
        //     {;}
        // }

#ifdef DEBUG
        //每秒运行一次，或者软件定时器创建一个Timer调用时间处理函数Time_Pros
        printf("usleep time_control_thread 1s.\r\n\r\n");
#endif
        usleep(1000000);
    }
}

void Timer1_Callback(void)
{
    /* 系统的时间处理 */
    SysTime_Pros(); //每秒加1，进位
    if(sys_Time_Display)
    {
        // 把系统时间发送到串口屏 每秒发送一次
        Display_Screen_Write_Time(Sys_Time.sys_time_years,0); //年
        Display_Screen_Write_Time(Sys_Time.sys_time_months,1); //月
        Display_Screen_Write_Time(Sys_Time.sys_time_days,2); //日
        Display_Screen_Write_Time(Sys_Time.sys_time_hours,5); //时
        Display_Screen_Write_Time(Sys_Time.sys_time_minutes,4); //分
        Display_Screen_Write_Time(Sys_Time.sys_time_seconds,3); //秒
    }

    /* 权限的时间处理 */
    Permission_Time_Pros(RC522_Database);

#ifdef DEBUG
    printf("usleep Timer1_Callback 1s.\r\n\r\n");
#endif
}

void scancard_iot_entry(void)
{
    mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, MSGQUEUE_OBJECTS_SIZE, NULL);
    if (mid_MsgQueue == NULL)
    {
        printf("Falied to create Message Queue!\n");
    }

    osThreadAttr_t attr;

    // 创建 主线程
    attr.name = "scancard_iot_thread";
    attr.attr_bits = 0U;
    attr.cb_mem= NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = SCANCARD_IOT_STACK_SIZE;
    attr.priority = SCANCARD_IOT_PRIO;

    if(osThreadNew((osThreadFunc_t)scancard_iot_thread, NULL, &attr) == NULL)
    {
        printf("[osThreadNew]Falied to create scancard_iot_thread Task.\r\n");
    }

    // 创建 刷卡(打卡)线程
    attr.name = "findcard_thread";
    attr.attr_bits = 0U;
    attr.cb_mem= NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = FINDCARD_STACK_SIZE;
    attr.priority = FINDCARD_PRIO;

    if(osThreadNew((osThreadFunc_t)findcard_thread, NULL, &attr) == NULL)
    {
        printf("[osThreadNew]Falied to create findcard_thread Task.\r\n");
    }

    // 创建 MQTT 线程
    attr.name = "MQTT_thread";
    attr.attr_bits = 0U;
    attr.cb_mem= NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = MQTT_STACK_SIZE;
    attr.priority = MQTT_PRIO;

    if((mqtt_thread_id = osThreadNew((osThreadFunc_t)MQTT_thread, NULL, &attr)) == NULL)
    {
        printf("[osThreadNew]Falied to create MQTT_thread Task.\r\n");
    }

    // 暂停 MQTT 线程，等待 wifi connect 开启。
    // wifi disconnect 也要暂停掉MQTT 线程
    // osThreadSuspend(mqtt_thread_id);

    // 创建 限时控制线程
    attr.name = "time_control_thread";
    attr.attr_bits = 0U;
    attr.cb_mem= NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = TIME_CONTROL_STACK_SIZE;
    attr.priority = TIME_CONTROL_PRIO;

    if(osThreadNew((osThreadFunc_t)time_control_thread, NULL, &attr) == NULL)
    {
        printf("[osThreadNew]Falied to create time_control_thread Task.\r\n");
    }

    // 创建 互斥量
    mutex_id1 = osMutexNew(NULL);
    if (mutex_id1 == NULL)
    {
        printf("Falied to create Mutex!\n");
    }
    mutex_id2 = osMutexNew(NULL);
    if (mutex_id2 == NULL)
    {
        printf("Falied to create Mutex!\n");
    }

    osTimerId_t id1;
    uint32_t timerDelay;
    osStatus_t status;

    // 创建 定时器（周期性，循环生效）
    id1 = osTimerNew((osTimerFunc_t)Timer1_Callback, osTimerPeriodic, NULL, NULL);
    if (id1 != NULL)  {
        timerDelay = 100U;                            // Hi3861 1U=10ms,100U=1S
        status = osTimerStart(id1, timerDelay);       // start timer
        if (status != osOK) {
        // Timer could not be started
        }
    }
}

// SYS_RUN(scancard_iot_entry);
APP_FEATURE_INIT(scancard_iot_entry);